package com.megaspacevr.controller;

import com.megaspacevr.entity.Bookings;
import com.megaspacevr.entity.Result;
import com.megaspacevr.entity.vo.BookingExportVO;
import com.megaspacevr.entity.vo.BookingRequestVO;
import com.megaspacevr.entity.vo.PageVO;
import com.megaspacevr.service.BookingsService;
import com.megaspacevr.utils.ResultUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * <p>
 * 预约表-预约记录 前端控制器
 * </p>
 *
 * @author yezi
 * @since 2025-06-17
 */
@Slf4j
@RestController
@Validated
@RequestMapping("/bookings")
@Tag(name = "预约管理", description = "VR展馆预约相关接口")
@CrossOrigin(origins = "*")
public class BookingsController {

    @Autowired
    private BookingsService bookingsService;

    @PostMapping("/book")
    @Operation(summary = "创建预约", description = "用户预约VR体验时间段")
    public Result<String> createBooking(@Valid @RequestBody BookingRequestVO bookingRequest) {
        
        log.info("收到预约请求：{}", bookingRequest);
        
        try {
//            // 检查用户是否已预约
//            if (bookingsService.hasUserBooked(bookingRequest.getUserToken(), bookingRequest.getContactPhone())) {
//                return ResultUtil.fail("您已经预约过了，每人仅限预约一次");
//            }
            
            // 转换为实体类
            Bookings bookings = new Bookings();
            BeanUtils.copyProperties(bookingRequest, bookings);
            
            // 创建预约
            boolean success = bookingsService.createBooking(bookings);
            
            if (success) {
                log.info("预约创建成功，预约编号：{}", bookings.getBookingNumber());
                return ResultUtil.success(bookings.getBookingNumber());
            } else {
                return ResultUtil.fail("预约失败，该时间段可能已满或不可用");
            }
            
        } catch (Exception e) {
            log.error("创建预约时发生异常", e);
            return ResultUtil.fail("预约失败，请稍后重试");
        }
    }

    @GetMapping("/check-user")
    @Operation(summary = "检查用户预约状态", description = "检查用户是否已经预约过")
    public Result<Boolean> checkUserBooking(
            @RequestParam("userToken") String userToken,
            @RequestParam("contactPhone") String contactPhone) {
        
        log.info("检查用户预约状态 - userToken: {}, phone: {}", userToken, contactPhone);
        
        try {
            boolean hasBooked = bookingsService.hasUserBooked(userToken, contactPhone);
            return ResultUtil.success(hasBooked);
        } catch (Exception e) {
            log.error("检查用户预约状态失败", e);
            return ResultUtil.fail("检查预约状态失败");
        }
    }

    @GetMapping("/booking-number/{bookingNumber}")
    @Operation(summary = "根据预约编号查询预约信息", description = "用户通过预约编号查询预约详情")
    public Result<Bookings> getBookingByNumber(@PathVariable String bookingNumber) {
        
        log.info("查询预约信息，预约编号：{}", bookingNumber);
        
        try {
            Bookings booking = bookingsService.lambdaQuery()
                    .eq(Bookings::getBookingNumber, bookingNumber)
                    .one();
            
            if (booking == null) {
                return ResultUtil.fail("预约记录不存在");
            }
            
            return ResultUtil.success(booking);
        } catch (Exception e) {
            log.error("查询预约信息失败", e);
            return ResultUtil.fail("查询预约信息失败");
        }
    }

    @GetMapping("/user-bookings")
    @Operation(summary = "获取用户预约记录", description = "根据用户Token获取用户的所有预约记录")
    public Result<List<Bookings>> getUserBookings(@RequestParam("userToken") String userToken) {
        
        log.info("获取用户预约记录 - userToken: {}", userToken);
        
        try {
            List<Bookings> bookings = bookingsService.getUserBookings(userToken);
            log.info("用户预约记录查询成功，共找到 {} 条记录", bookings.size());
            return ResultUtil.success(bookings);
        } catch (Exception e) {
            log.error("获取用户预约记录失败", e);
            return ResultUtil.fail("获取预约记录失败，请稍后重试");
        }
    }

    @PutMapping("/cancel/{bookingId}")
    @Operation(summary = "取消预约", description = "用户取消指定的预约")
    public Result<String> cancelBooking(
            @PathVariable("bookingId") Long bookingId,
            @RequestParam("userToken") String userToken) {
        
        log.info("取消预约请求 - bookingId: {}, userToken: {}", bookingId, userToken);
        
        try {
            boolean success = bookingsService.cancelBooking(bookingId, userToken);
            
            if (success) {
                log.info("预约取消成功 - bookingId: {}", bookingId);
                return ResultUtil.success("预约已成功取消");
            } else {
                return ResultUtil.fail("取消预约失败，预约不存在或您没有权限取消此预约");
            }
            
        } catch (Exception e) {
            log.error("取消预约时发生异常 - bookingId: {}", bookingId, e);
            return ResultUtil.fail("取消预约失败，请稍后重试");
        }
    }

    // 管理员接口
    @GetMapping("/admin/getBookings")
    @Operation(summary = "管理员查询预约列表", description = "管理员分页查询预约数据，支持多条件筛选，包含完整个人信息")
    public Result<PageVO<BookingExportVO>> getBookingsForAdmin(
            Integer pageNum,
            Integer pageSize,
            @RequestParam(required = false) String searchText,
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) String periodName,
            @RequestParam(required = false, defaultValue = "desc") String sortType) {
        
        log.info("管理员查询预约列表 - 页码: {}, 页大小: {}, 搜索: {}", pageNum, pageSize, searchText);
        
        PageVO<BookingExportVO> bookings = bookingsService.getBookingsForAdminWithFullInfo(
            pageNum, pageSize, searchText, startDate, endDate, status, periodName, sortType);
        return ResultUtil.success(bookings);
    }

    @GetMapping("/admin/exportBookings")
    @Operation(summary = "导出预约数据Excel", description = "管理员导出预约数据为Excel文件")
    public ResponseEntity<byte[]> exportBookings(
            @RequestParam(required = false) String searchText,
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate,
            @RequestParam(required = false) String status,
            @RequestParam(required = false) String periodName,
            @RequestParam(required = false, defaultValue = "desc") String sortType) throws IOException {
        
        log.info("开始导出预约列表Excel，参数：searchText={}, startDate={}, endDate={}, status={}, periodName={}, sortType={}",
                searchText, startDate, endDate, status, periodName, sortType);

        try {
            // 获取预约列表数据（包含完整个人信息）
            List<BookingExportVO> bookingsList = bookingsService.getBookingsForExport(
                searchText, startDate, endDate, status, periodName, sortType);
            log.info("获取到 {} 条数据", bookingsList.size());

            // 创建工作簿
            try (XSSFWorkbook workbook = new XSSFWorkbook()) {
                Sheet sheet = workbook.createSheet("预约列表");

                // 设置表头样式
                CellStyle headerStyle = workbook.createCellStyle();
                headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
                headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                Font headerFont = workbook.createFont();
                headerFont.setBold(true);
                headerStyle.setFont(headerFont);

                // 创建表头
                Row headerRow = sheet.createRow(0);
                String[] header = {"预约编号", "联系人姓名", "联系电话", "性别", "年龄", "教育程度", 
                                 "职业", "宗教信仰", "掌握语种", "预约日期", "预约时段", 
                                 "开始时间", "结束时间", "预约状态", "创建时间", "备注", "特殊需求"};

                for (int i = 0; i < header.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(header[i]);
                    cell.setCellStyle(headerStyle);
                    sheet.autoSizeColumn(i);
                }

                // 填充数据
                int rowNum = 1;
                for (BookingExportVO booking : bookingsList) {
                    Row row = sheet.createRow(rowNum++);
                    
                    // 基本预约信息
                    row.createCell(0).setCellValue(booking.getBookingNumber() != null ? booking.getBookingNumber() : "");
                    row.createCell(1).setCellValue(booking.getContactName() != null ? booking.getContactName() : "");
                    row.createCell(2).setCellValue(booking.getContactPhone() != null ? booking.getContactPhone() : "");
                    
                    // 个人详细信息
                    row.createCell(3).setCellValue(booking.getGender() != null ? booking.getGender() : "");
                    row.createCell(4).setCellValue(booking.getAge() != null ? booking.getAge().toString() : "");
                    row.createCell(5).setCellValue(booking.getEducation() != null ? booking.getEducation() : "");
                    row.createCell(6).setCellValue(booking.getOccupation() != null ? booking.getOccupation() : "");
                    row.createCell(7).setCellValue(booking.getReligion() != null ? booking.getReligion() : "");
                    row.createCell(8).setCellValue(booking.getLanguages() != null ? booking.getLanguages() : "");
                    
                    // 预约时间信息
                    row.createCell(9).setCellValue(booking.getBookingDate() != null ? booking.getBookingDate().toString() : "");
                    row.createCell(10).setCellValue(booking.getPeriodName() != null ? booking.getPeriodName() : "");
                    row.createCell(11).setCellValue(booking.getBookingTimeStart() != null ? booking.getBookingTimeStart().toString() : "");
                    row.createCell(12).setCellValue(booking.getBookingTimeEnd() != null ? booking.getBookingTimeEnd().toString() : "");
                    row.createCell(13).setCellValue(booking.getStatus() != null ? booking.getStatus() : "");
                    
                    // 设置创建时间
                    Cell createTimeCell = row.createCell(14);
                    if (booking.getCreatedAt() != null) {
                        createTimeCell.setCellValue(booking.getCreatedAt());
                        CellStyle dateStyle = workbook.createCellStyle();
                        dateStyle.setDataFormat(workbook.createDataFormat().getFormat("yyyy-mm-dd hh:mm"));
                        createTimeCell.setCellStyle(dateStyle);
                    }
                    
                    // 备注和特殊需求
                    row.createCell(15).setCellValue(booking.getNotes() != null ? booking.getNotes() : "");
                    row.createCell(16).setCellValue(booking.getSpecialRequirements() != null ? booking.getSpecialRequirements() : "");
                }

                // 写入字节数组
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                workbook.write(outputStream);
                byte[] content = outputStream.toByteArray();

                // 设置响应头
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
                String filename = URLEncoder.encode("VR展馆预约列表.xlsx", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
                headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + filename);

                log.info("Excel文件生成成功，大小: {} bytes", content.length);
                return new ResponseEntity<>(content, headers, HttpStatus.OK);
            }
        } catch (Exception e) {
            log.error("导出Excel失败", e);
            throw new RuntimeException("导出Excel失败: " + e.getMessage());
        }
    }
}
